package fr.gdi.android.news;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

import com.android.extras.ExtMatrixCursor;

import fr.gdi.android.news.utils.Constants;
import fr.gdi.android.news.utils.Constants.Preferences;
import fr.gdi.android.news.utils.Constants.Provider;
import fr.gdi.android.news.utils.Constants.Provider.Columns;
import fr.gdi.android.news.utils.Constants.URI;
import fr.gdi.android.news.utils.FeedUtils;
import fr.gdi.android.news.utils.PreferenceUtils;

public class NewsProvider extends ContentProvider
{
    private static Context ctx = null;
    
    private SQLiteDatabase database;
    
    static
    {
        // URI.MATCHER.addURI(URI.AUTHORITY, "news", URI.FEEDS);
        URI.MATCHER.addURI(URI.AUTHORITY, "news/#", URI.SINGLE_FEED);
        URI.MATCHER.addURI(URI.AUTHORITY, "widget/#", URI.WIDGET_FEEDS);
    }
    
    @Override
    public boolean onCreate()
    {
        ctx = getContext();
        
        DatabaseHelper dbHelper = new DatabaseHelper(ctx);
        database = dbHelper.getWritableDatabase();
        
        boolean success = database == null ? false : true;
        
        return success;
    }
    
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs)
    {
        return 0;
    }
    
    @Override
    public String getType(Uri uri)
    {
        return null;
    }
    
    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        return null;
    }
    
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    {
        Integer appWidgetId = null;
        List<String> feeds = new ArrayList<String>();
        
        if (URI.MATCHER.match(uri) == URI.WIDGET_FEEDS)
        {
            List<String> pathSegs = uri.getPathSegments();
            appWidgetId = Integer.parseInt(pathSegs.get(pathSegs.size() - 1));
            feeds = FeedUtils.getFeedNames(ctx, appWidgetId);
        }
        else if (URI.MATCHER.match(uri) == URI.SINGLE_FEED)
        {
            List<String> pathSegs = uri.getPathSegments();
            String feed = pathSegs.get(pathSegs.size() - 1);
            feeds.add(feed);
        }
        else
        {
            feeds.addAll(FeedUtils.getAllFeedNames(ctx));
        }
        
        Cursor cursor = selectRows(ctx, feeds, appWidgetId);
        
        cursor.setNotificationUri(ctx.getContentResolver(), uri);
        
        return cursor;
    }
    
    private Cursor selectRows(Context ctx, List<String> feeds, Integer appWidgetId)
    {
        DatabaseHelper.lock();
        try
        {
            StringBuilder sqlBuilder = new StringBuilder("select ");
            
            for (int i = 0, l = Provider.PROJECTION_APPWIDGETS.length; i < l; i++)
            {
                if (i != 0) sqlBuilder.append(", ");
                String col = Provider.PROJECTION_APPWIDGETS[i];
                sqlBuilder.append("n.").append(col).append(" as ").append(col);
            }
            
            sqlBuilder.append(", c.color as color")
                      .append(" from ").append(DatabaseHelper.NEWS_TABLE).append(" n")
                      .append(" left join ").append(DatabaseHelper.COLOR_TABLE).append(" c on ")
                      .append("c.").append(Provider.Columns.FEED_NAME.toString()).append("=")
                      .append("n.").append(Provider.Columns.FEED_NAME.toString());
            
            sqlBuilder.append(" where n.").append(Provider.Columns.FEED_NAME.toString()).append(" in (");
            
            String[] selectionArgs = new String[feeds.size()];
            for (int i = 0, l = feeds.size(); i < l; i++)
            {
                if (i != 0) sqlBuilder.append(", ");
                sqlBuilder.append("?");
                selectionArgs[i] = feeds.get(i);
            }
            
            sqlBuilder.append(") order by ").append(Provider.Columns.NEWS_DATE.toString()).append(" DESC");
            
            int limit = PreferenceUtils.getIntFromStringPreference(ctx, Preferences.MAX_FEEDS, appWidgetId);
            //sqlBuilder.append(" limit ").append(limit);
            
            String query = sqlBuilder.toString();
            
            Cursor cursor = null, debugCursor = null;
            
            ExtMatrixCursor detachedCursor = new ExtMatrixCursor(Provider.PROJECTION_APPWIDGETS);
            try
            {
                cursor = database.rawQuery(query, selectionArgs);
                if (Constants.USE_EMULATOR)
                {
                    debugCursor = database.rawQuery("select count(*) c from news", new String[0]);
                    boolean hasFirst = debugCursor.moveToFirst();
                    if (hasFirst) Log.d(this.getClass().getName(), "News count: " + debugCursor.getInt(0));
                }
                
                List<String> titles = new ArrayList<String>();
                List<SimpleNewsEntry> entries = new ArrayList<SimpleNewsEntry>();
                while (cursor.moveToNext())
                {
                    int colIndex = cursor.getColumnIndex(Columns.NEWS_TITLE.toString());
                    String title = cursor.getString(colIndex);
                    if ( titles.contains(title) ) continue;
                    
                    titles.add(title);
                    Map<String, String> map = new HashMap<String, String>();
                    for (int u = 0, l = Provider.PROJECTION_APPWIDGETS.length; u < l; u++)
                    {
                        String col = Provider.PROJECTION_APPWIDGETS[u];
                        int index = cursor.getColumnIndex(col);
                        if ( index < 0 ) 
                        {
                            String columns = Arrays.toString(cursor.getColumnNames());
                            Log.w(getClass().getName(), "Expected " + col + " not found in ResultSet! Columns: " + columns);
                        }
                        else
                        {
                            String s = cursor.getString(index);
                            map.put(col, s);
                        }
                    }
                    
                    SimpleNewsEntry entry = new SimpleNewsEntry(map);
                    int colorIndex = cursor.getColumnIndex("color");
                    if ( !cursor.isNull(colorIndex) ) 
                    {
                        entry.setHeadlineColor(cursor.getInt(colorIndex));
                    }
                    entries.add(entry);
                }
                
                int k = 0;
                for (SimpleNewsEntry entry : entries)
                {
                    k++;
                    detachedCursor.addRow(entry.toArray(ctx, appWidgetId));
                    if ( k == limit ) break;
                }
            }
            finally
            {
                if (cursor != null) cursor.close();
                if (debugCursor != null) debugCursor.close();
            }
            
            return detachedCursor;
        }
        finally
        {
            DatabaseHelper.unlock();
        }
    }
    
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
    {
        return 0;
    }
    
    public static SimpleNewsEntry getNewsEntry(String url)
    {
        StringBuilder sqlBuilder = new StringBuilder("select ");
        
        sqlBuilder.append(Provider.Columns.NEWS_TITLE.toString()).append(" from ").append(DatabaseHelper.NEWS_TABLE).append(" where ").append(
                Provider.Columns.NEWS_LINK.toString()).append(" = ?").append(" limit 1 ");
        
        SQLiteDatabase db = null;
        String title = "";
        
        DatabaseHelper.lock();
        Cursor cursor = null;
        try
        {
            db = new DatabaseHelper(ctx).getReadableDatabase();
            
            cursor = db.rawQuery(sqlBuilder.toString(), new String[] { url });
            
            boolean hasFirst = cursor.moveToFirst();
            
            if (hasFirst) title = cursor.getString(0);
        }
        finally
        {
            if ( cursor != null ) cursor.close();
            db.close();
            DatabaseHelper.unlock();
        }
        
        return new SimpleNewsEntry(url, title);
    }
}
